<?php
declare (strict_types = 1);

namespace app\controller;

use app\BaseController;
use app\service\NanobananaApiService;
use app\service\PointsService;
use think\facade\Db;
use think\facade\Log;
use think\facade\Validate;
use think\facade\Config;
use think\App;

class Nanobanana extends BaseController
{
    protected $nanobananaService;

    public function __construct(NanobananaApiService $nanobananaService,App $app)
    {
        parent::__construct($app);
        $this->nanobananaService = $nanobananaService;
    }

    /**
     * Nanobanana API回调处理
     * 处理图片生成完成后的回调通知
     */
    public function callback()
    {
        // 处理 OPTIONS 预检请求
        if ($this->request->method() == 'OPTIONS') {
            return json(['code' => 200, 'msg' => 'OK']);
        }
        
        try {
            // 获取POST数据（可能是JSON格式）
            $rawData = $this->request->getContent();
            $data = json_decode($rawData, true);
            
            // 如果JSON解析失败，尝试从POST参数获取
            if (empty($data)) {
                $data = $this->request->post();
            }

            // 记录回调日志
            Log::info('Nanobanana回调接收', [
                'raw_data' => $rawData,
                'parsed_data' => $data,
                'headers' => $this->request->header()
            ]);

            // 验证回调数据
            if (empty($data)) {
                Log::error('Nanobanana回调数据为空');
                return json(['code' => 400, 'msg' => '回调数据为空']);
            }

            // 检查必要字段
            if (!isset($data['code']) || !isset($data['data']['taskId'])) {
                Log::error('Nanobanana回调数据格式错误', ['data' => $data]);
                return json(['code' => 400, 'msg' => '回调数据格式错误']);
            }

            $code = $data['code'];
            $taskId = $data['data']['taskId'];
            $message = $data['msg'] ?? '';

            // 查找任务记录
            $task = Db::name('nanobanana_tasks')
                ->where('task_id', $taskId)
                ->find();

            if (!$task) {
                Log::warning('Nanobanana回调：任务不存在', ['task_id' => $taskId]);
                return json(['code' => 404, 'msg' => '任务不存在']);
            }

            // 如果任务已经完成，不再处理
            if ($task['status'] == 2) {
                Log::info('Nanobanana回调：任务已完成，跳过处理', ['task_id' => $taskId]);
                return json(['code' => 200, 'msg' => '任务已完成']);
            }

            $updateData = [
                'update_time' => date('Y-m-d H:i:s')
            ];

            // 根据返回码处理
            switch ($code) {
                case 200:
                    // 成功 - 图片生成成功
                    $resultImageUrl = $data['data']['info']['resultImageUrl'] ?? '';
                    
                    if (empty($resultImageUrl)) {
                        Log::warning('Nanobanana回调：成功但resultImageUrl为空', [
                            'task_id' => $taskId,
                            'data' => $data
                        ]);
                        // 即使成功但URL为空，也标记为失败
                        $updateData['status'] = 3;
                        $updateData['error_msg'] = '生成成功但结果图片URL为空';
                        $updateData['complete_time'] = date('Y-m-d H:i:s');
                    } else {
                        // 更新任务状态和结果
                        $updateData['status'] = 2; // 成功
                        $updateData['result_image_url'] = $resultImageUrl;
                        $updateData['complete_time'] = date('Y-m-d H:i:s');
                    }

                    // 更新数据库
                    Db::name('nanobanana_tasks')
                        ->where('task_id', $taskId)
                        ->update($updateData);

                    Log::info('Nanobanana回调处理成功', [
                        'task_id' => $taskId,
                        'result_image_url' => $resultImageUrl
                    ]);

                    return json(['code' => 200, 'msg' => '处理成功']);

                case 400:
                    // 失败 - 提示词违反内容政策（不退还积分，因为是用户问题）
                    $errorMsg = $message ?: '提示词违反内容政策';
                    
                    $updateData['status'] = 3; // 失败
                    $updateData['error_msg'] = $errorMsg;
                    $updateData['complete_time'] = date('Y-m-d H:i:s');

                    Db::name('nanobanana_tasks')
                        ->where('task_id', $taskId)
                        ->update($updateData);

                    Log::warning('Nanobanana回调：提示词违反内容政策', [
                        'task_id' => $taskId,
                        'code' => $code,
                        'error_msg' => $errorMsg
                    ]);

                    return json(['code' => 200, 'msg' => '失败状态已记录']);

                case 500:
                    // 失败 - 内部错误，请稍后重试（退还积分）
                    $errorMsg = $message ?: '内部错误，请稍后重试';
                    
                    $this->handleTaskFailure($task, $errorMsg, true);

                    Log::error('Nanobanana回调：内部错误', [
                        'task_id' => $taskId,
                        'code' => $code,
                        'error_msg' => $errorMsg
                    ]);

                    return json(['code' => 200, 'msg' => '失败状态已记录']);

                case 501:
                    // 失败 - 图片生成任务失败（退还积分）
                    $errorMsg = $message ?: '图片生成任务失败';
                    
                    $this->handleTaskFailure($task, $errorMsg, true);

                    Log::error('Nanobanana回调：图片生成任务失败', [
                        'task_id' => $taskId,
                        'code' => $code,
                        'error_msg' => $errorMsg
                    ]);

                    return json(['code' => 200, 'msg' => '失败状态已记录']);

                default:
                    // 未知状态码
                    $errorMsg = $message ?: ('未知错误，状态码：' . $code);
                    
                    $updateData['status'] = 3; // 失败
                    $updateData['error_msg'] = $errorMsg;
                    $updateData['complete_time'] = date('Y-m-d H:i:s');

                    Db::name('nanobanana_tasks')
                        ->where('task_id', $taskId)
                        ->update($updateData);

                    Log::warning('Nanobanana回调：未知状态码', [
                        'task_id' => $taskId,
                        'code' => $code,
                        'error_msg' => $errorMsg,
                        'data' => $data
                    ]);

                    return json(['code' => 200, 'msg' => '失败状态已记录']);
            }

        } catch (\Exception $e) {
            Log::error('Nanobanana回调处理异常', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            return json(['code' => 500, 'msg' => '处理异常：' . $e->getMessage()]);
        }
    }

    /**
     * 提交图片生成任务（标准接口）
     */
    public function generate()
    {
        try {
            // 检查用户认证
            if (!isset($this->request->user) || !$this->request->user) {
                return json(['code' => 401, 'msg' => '用户未登录，请先登录']);
            }
            
            $userId = $this->request->user->uid;
            $data = $this->request->post();

            // 验证数据
            $validate = Validate::rule([
                'prompt' => 'require',
                'type' => 'in:TEXTTOIAMGE,IMAGETOIAMGE'
            ]);

            if (!$validate->check($data)) {
                return json(['code' => 400, 'msg' => $validate->getError()]);
            }

            $prompt = $data['prompt'];
            $type = $data['type'] ?? 'TEXTTOIAMGE';
            $options = [
                'numImages' => $data['numImages'] ?? 1,
                'image_size' => $data['aspectRatio'] ?? '16:9',
            ];

            // 如果提供了回调URL，使用自定义回调，否则使用默认回调
            if (!empty($data['callBackUrl'])) {
                $options['callBackUrl'] = $data['callBackUrl'];
            } else {
                // 生成默认回调URL
                $scheme = $this->request->scheme();
                $host = $this->request->host();
                $options['callBackUrl'] = $scheme . '://' . $host . '/server/nanobanana/callback';
            }

            // 如果提供了 imageUrls，添加到选项中
            if (!empty($data['imageUrls']) && is_array($data['imageUrls'])) {
                $options['imageUrls'] = $data['imageUrls'];
            }

            // 计算所需积分（generate固定0.5积分）
            $pointsService = new PointsService();
            $needPoints = 0.5;

            // 检查积分
            $userPoints = $pointsService->getUserPoints($userId);
            if ($userPoints < $needPoints) {
                return json([
                    'code' => 400,
                    'msg' => "积分不足，需要{$needPoints}积分，当前余额{$userPoints}积分"
                ]);
            }

            // 事务处理：扣除积分 + 调用API + 保存任务
            Db::startTrans();
            try {
                // 调用API生成图片
                $result = $this->nanobananaService->generate($prompt, $type, $options);
                
                // 获取远程任务ID
                $remoteTaskId = $result['data']['taskId'] ?? '';
                if (empty($remoteTaskId)) {
                    throw new \Exception('API返回的taskId为空');
                }

                // 扣除积分
                $pointsService->consume($userId, $needPoints, "Nanobanana生成任务({$type})");

                // 保存任务记录
            $taskData = [
                'user_id' => $userId,
                'task_id' => $remoteTaskId,
                'type' => $type,
                'prompt' => $prompt,
                'num_images' => $options['numImages'],
                'image_size' => $options['image_size'],
                'status' => 1, // 生成中
                'points_consumed' => $needPoints,
                'create_time' => date('Y-m-d H:i:s'),
                'update_time' => date('Y-m-d H:i:s'),
            ];

                // 如果有图片URL数组，保存到数据库
                if (!empty($options['imageUrls']) && is_array($options['imageUrls'])) {
                    $taskData['image_urls'] = json_encode($options['imageUrls']);
                }

                $taskId = Db::name('nanobanana_tasks')->insertGetId($taskData);

                Db::commit();

                return json([
                    'code' => 200,
                    'msg' => '任务提交成功',
                    'data' => [
                        'id' => $taskId,
                        'task_id' => $remoteTaskId,
                        'prompt' => $prompt,
                        'type' => $type,
                        'num_images' => $options['numImages'],
                        'image_size' => $options['image_size'],
                        'points_consumed' => $needPoints,
                        'status' => 1,
                        'status_text' => '生成中'
                    ]
                ]);

            } catch (\Exception $e) {
                Db::rollback();
                throw $e;
            }

        } catch (\Exception $e) {
            Log::error('Nanobanana生成任务提交失败', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            return json(['code' => 500, 'msg' => '提交失败：' . $e->getMessage()]);
        }
    }

    /**
     * 查询任务状态
     */
    public function query()
    {
        try {
            // 检查用户认证
            if (!isset($this->request->user) || !$this->request->user) {
                return json(['code' => 401, 'msg' => '用户未登录，请先登录']);
            }
            
            $userId = $this->request->user->uid;
            $taskId = $this->request->param('task_id');

            if (empty($taskId)) {
                return json(['code' => 400, 'msg' => 'task_id不能为空']);
            }

            $task = Db::name('nanobanana_tasks')
                ->where('task_id', $taskId)
                ->where('user_id', $userId)
                ->find();

            if (!$task) {
                return json(['code' => 404, 'msg' => '任务不存在']);
            }

            // 处理JSON字段
            if (!empty($task['image_urls'])) {
                $task['image_urls'] = json_decode($task['image_urls'], true);
            }

            return json([
                'code' => 200,
                'msg' => '获取成功',
                'data' => $task
            ]);

        } catch (\Exception $e) {
            Log::error('Nanobanana任务查询失败', [
                'error' => $e->getMessage()
            ]);
            return json(['code' => 500, 'msg' => '查询失败：' . $e->getMessage()]);
        }
    }

    /**
     * 获取任务列表
     */
    public function list()
    {
        try {
            // 检查用户认证
            if (!isset($this->request->user) || !$this->request->user) {
                return json(['code' => 401, 'msg' => '用户未登录，请先登录']);
            }
            
            $userId = $this->request->user->uid;
            $page = intval($this->request->param('page', 1));
            $limit = intval($this->request->param('limit') ?? $this->request->param('pageSize', 10));
            $status = $this->request->param('status'); // 可选：按状态筛选

            $query = Db::name('nanobanana_tasks')
                ->where('user_id', $userId);

            // 按状态筛选
            if ($status !== null && $status !== '') {
                $query->where('status', $status);
            }

            // 先计算总数
            $total = $query->count();

            // 再分页查询
            $tasks = $query->order('create_time', 'desc')
                ->page($page, $limit)
                ->select();

            // 处理JSON字段和状态文本
            foreach ($tasks as &$task) {
                if (!empty($task['image_urls'])) {
                    $task['image_urls'] = json_decode($task['image_urls'], true);
                }
                $task['status_text'] = $this->getStatusText($task['status']);
            }

            return json([
                'code' => 200,
                'msg' => '获取成功',
                'data' => [
                    'list' => $tasks,
                    'total' => $total,
                    'page' => $page,
                    'limit' => $limit
                ]
            ]);

        } catch (\Exception $e) {
            Log::error('Nanobanana任务列表查询失败', [
                'error' => $e->getMessage()
            ]);
            return json(['code' => 500, 'msg' => '查询失败：' . $e->getMessage()]);
        }
    }

    /**
     * 文生图接口（用户友好）
     * 扣除积分：每张图0.5积分
     */
    public function textToImage()
    {
        try {
            // 检查用户认证
            if (!isset($this->request->user) || !$this->request->user) {
                return json(['code' => 401, 'msg' => '用户未登录，请先登录']);
            }
            
            $userId = $this->request->user->uid;
            $data = $this->request->post();

            // 验证数据
            $validate = Validate::rule([
                'prompt' => 'require|max:1000',
                'numImages' => 'integer|between:1,4',
                'image_size' => 'in:1:1,16:9,9:16,4:3,3:4',
                'aspectRatio' => 'in:1:1,16:9,9:16,4:3,3:4',
                'resolution' => 'in:2K,4K'
            ]);

            if (!$validate->check($data)) {
                return json(['code' => 400, 'msg' => $validate->getError()]);
            }

            $prompt = trim($data['prompt']);
            $numImages = intval($data['numImages'] ?? 1);
            $imageSize = $data['aspectRatio'] ?? $data['aspectRatio'] ?? '16:9';
            $resolution = $data['resolution'] ?? '2K';

            // 计算所需积分（textToImage固定1.5积分）
            $pointsService = new PointsService();
            $needPoints = 1.5;

            // 检查积分
            $userPoints = $pointsService->getUserPoints($userId);
            if ($userPoints < $needPoints) {
                return json([
                    'code' => 400,
                    'msg' => "积分不足，需要{$needPoints}积分，当前余额{$userPoints}积分"
                ]);
            }

            // 生成默认回调URL
            $scheme = $this->request->scheme();
            $host = $this->request->host();
            $callBackUrl = $scheme . '://' . $host . '/server/nanobanana/callback';

            $options = [
                'aspectRatio' => $imageSize,
                'resolution' => $resolution,
                'callBackUrl' => $callBackUrl
            ];
            
            // 如果提供了 imageUrls，添加到选项中
            if (!empty($data['imageUrls']) && is_array($data['imageUrls'])) {
                $options['imageUrls'] = $data['imageUrls'];
            }

            // 事务处理：扣除积分 + 调用API + 保存任务
            Db::startTrans();
            try {
                // 调用API生成图片
                $result = $this->nanobananaService->textToImage($prompt, $options);
                Log::info('Nanobanana API响应' . var_export($result, true));
                $remoteTaskId = $result['data']['taskId'] ?? '';
                if (empty($remoteTaskId)) {
                    throw new \Exception('API返回的taskId为空');
                }

                // 扣除积分
                $pointsService->consume($userId, $needPoints, "Nanobanana文生图({$numImages}张)");

                // 保存任务记录
                $taskData = [
                    'user_id' => $userId,
                    'task_id' => $remoteTaskId,
                    'type' => 'TEXTTOIAMGE',
                    'prompt' => $prompt,
                    'num_images' => $numImages,
                    'image_size' => $imageSize,
                    'status' => 1, // 生成中
                    'points_consumed' => $needPoints,
                    'create_time' => date('Y-m-d H:i:s'),
                    'update_time' => date('Y-m-d H:i:s'),
                ];

                $taskId = Db::name('nanobanana_tasks')->insertGetId($taskData);

                Db::commit();

                return json([
                    'code' => 200,
                    'msg' => '任务提交成功',
                    'data' => [
                        'id' => $taskId,
                        'task_id' => $remoteTaskId,
                        'prompt' => $prompt,
                        'num_images' => $numImages,
                        'image_size' => $imageSize,
                        'points_consumed' => $needPoints,
                        'status' => 1,
                        'status_text' => '生成中'
                    ]
                ]);

            } catch (\Exception $e) {
                Db::rollback();
                throw $e;
            }

        } catch (\Exception $e) {
            Log::error('Nanobanana文生图失败', [
                'user_id' => $userId ?? 0,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            return json(['code' => 500, 'msg' => '提交失败：' . $e->getMessage()]);
        }
    }

    /**
     * 图生图接口（用户友好）
     * 扣除积分：每张图0.5积分
     */
    public function imageToImage()
    {
        try {
            // 检查用户认证
            if (!isset($this->request->user) || !$this->request->user) {
                return json(['code' => 401, 'msg' => '用户未登录，请先登录']);
            }
            
            $userId = $this->request->user->uid;
            $data = $this->request->post();

            // 验证数据
            $validate = Validate::rule([
                'prompt' => 'require|max:1000',
                'imageUrls' => 'require|array',
                'imageUrls.*' => 'url',
                'numImages' => 'integer|between:1,4',
                'image_size' => 'in:1:1,16:9,9:16,4:3,3:4',
                'aspectRatio' => 'in:1:1,16:9,9:16,4:3,3:4',
                'resolution' => 'in:2K,4K'
            ]);

            if (!$validate->check($data)) {
                return json(['code' => 400, 'msg' => $validate->getError()]);
            }

            $prompt = trim($data['prompt']);
            $imageUrls = $data['imageUrls'];
            $numImages = intval($data['numImages'] ?? 1);
            $imageSize = $data['image_size'] ?? $data['aspectRatio'] ?? '16:9';
            $resolution = $data['resolution'] ?? '2K';

            // 验证图片URL数组
            if (empty($imageUrls) || !is_array($imageUrls)) {
                return json(['code' => 400, 'msg' => 'imageUrls必须是非空数组']);
            }

            // 计算所需积分（每张图0.5积分）
            $pointsService = new PointsService();
            $unitPoints = Config::get('points.points.nanobanana.points', 0.5);
            $needPoints = $unitPoints * $numImages;

            // 检查积分
            $userPoints = $pointsService->getUserPoints($userId);
            if ($userPoints < $needPoints) {
                return json([
                    'code' => 400,
                    'msg' => "积分不足，需要{$needPoints}积分，当前余额{$userPoints}积分"
                ]);
            }

            // 生成默认回调URL
            $scheme = $this->request->scheme();
            $host = $this->request->host();
            $callBackUrl = $scheme . '://' . $host . '/api/nanobanana/callback';

            $options = [
                'aspectRatio' => $imageSize,
                'resolution' => $resolution,
                'callBackUrl' => $callBackUrl,
                'imageUrls' => $imageUrls
            ];

            // 事务处理：扣除积分 + 调用API + 保存任务
            Db::startTrans();
            try {
                // 调用API生成图片
                $result = $this->nanobananaService->imageToImage($prompt, $imageUrls, $options);
                
                $remoteTaskId = $result['data']['taskId'] ?? '';
                if (empty($remoteTaskId)) {
                    throw new \Exception('API返回的taskId为空');
                }

                // 扣除积分
                $pointsService->consume($userId, $needPoints, "Nanobanana图生图({$numImages}张)");

                // 保存任务记录
                $taskData = [
                    'user_id' => $userId,
                    'task_id' => $remoteTaskId,
                    'type' => 'IMAGETOIAMGE',
                    'prompt' => $prompt,
                    'num_images' => $numImages,
                    'image_size' => $imageSize,
                    'image_urls' => json_encode($imageUrls),
                    'status' => 1, // 生成中
                    'points_consumed' => $needPoints,
                    'create_time' => date('Y-m-d H:i:s'),
                    'update_time' => date('Y-m-d H:i:s'),
                ];

                $taskId = Db::name('nanobanana_tasks')->insertGetId($taskData);

                Db::commit();

                return json([
                    'code' => 200,
                    'msg' => '任务提交成功',
                    'data' => [
                        'id' => $taskId,
                        'task_id' => $remoteTaskId,
                        'prompt' => $prompt,
                        'num_images' => $numImages,
                        'image_size' => $imageSize,
                        'points_consumed' => $needPoints,
                        'status' => 1,
                        'status_text' => '生成中'
                    ]
                ]);

            } catch (\Exception $e) {
                Db::rollback();
                throw $e;
            }

        } catch (\Exception $e) {
            Log::error('Nanobanana图生图失败', [
                'user_id' => $userId ?? 0,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            return json(['code' => 500, 'msg' => '提交失败：' . $e->getMessage()]);
        }
    }

    /**
     * 获取提示词预设列表
     */
    public function getPrompts()
    {
        try {
            $category = $this->request->param('category'); // 可选：按分类筛选

            $query = Db::name('nanobanana_prompts')
                ->where('status', 1); // 只返回启用的

            // 按分类筛选
            if (!empty($category)) {
                $query->where('category', $category);
            }

            $prompts = $query->order('sort', 'desc')
                ->order('id', 'asc')
                ->select();

            // 按分类分组
            $grouped = [];
            foreach ($prompts as $prompt) {
                $cat = $prompt['category'] ?? 'other';
                if (!isset($grouped[$cat])) {
                    $grouped[$cat] = [];
                }
                $grouped[$cat][] = $prompt;
            }

            return json([
                'code' => 200,
                'msg' => '获取成功',
                'data' => [
                    'list' => $prompts,
                    'grouped' => $grouped,
                    'categories' => array_keys($grouped)
                ]
            ]);

        } catch (\Exception $e) {
            Log::error('Nanobanana提示词列表查询失败', [
                'error' => $e->getMessage()
            ]);
            return json(['code' => 500, 'msg' => '查询失败：' . $e->getMessage()]);
        }
    }

    /**
     * 获取提示词分类列表
     */
    public function getPromptCategories()
    {
        try {
            $categories = Db::name('nanobanana_prompts')
                ->where('status', 1)
                ->group('category')
                ->column('category');

            $categoryNames = [
                'product' => '产品展示',
                'product_showcase' => '产品特写',
                'lifestyle' => '生活方式',
                'scene' => '场景',
                'background' => '背景',
                'other' => '其他'
            ];

            $result = [];
            foreach ($categories as $cat) {
                $result[] = [
                    'value' => $cat,
                    'name' => $categoryNames[$cat] ?? $cat
                ];
            }

            return json([
                'code' => 200,
                'msg' => '获取成功',
                'data' => $result
            ]);

        } catch (\Exception $e) {
            Log::error('Nanobanana提示词分类查询失败', [
                'error' => $e->getMessage()
            ]);
            return json(['code' => 500, 'msg' => '查询失败：' . $e->getMessage()]);
        }
    }

    /**
     * 处理任务失败（更新状态并可选退还积分）
     */
    private function handleTaskFailure($task, $errorMsg, $refundPoints = false)
    {
        $updateData = [
            'status' => 3, // 失败
            'error_msg' => $errorMsg,
            'complete_time' => date('Y-m-d H:i:s'),
            'update_time' => date('Y-m-d H:i:s')
        ];

        Db::startTrans();
        try {
            // 更新任务状态
            Db::name('nanobanana_tasks')
                ->where('task_id', $task['task_id'])
                ->update($updateData);

            // 如果需要退还积分
            if ($refundPoints && $task['points_consumed'] > 0) {
                $pointsService = new PointsService();
                $pointsService->recharge(
                    $task['user_id'],
                    $task['points_consumed'],
                    '',
                    "Nanobanana任务{$task['task_id']}失败退还积分"
                );
                Log::info('Nanobanana任务失败已退还积分', [
                    'task_id' => $task['task_id'],
                    'user_id' => $task['user_id'],
                    'points' => $task['points_consumed']
                ]);
            }

            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            Log::error('Nanobanana任务失败处理异常', [
                'task_id' => $task['task_id'],
                'error' => $e->getMessage()
            ]);
        }
    }

    /**
     * 获取状态文本
     */
    private function getStatusText($status)
    {
        $statusTexts = [
            0 => '待处理',
            1 => '生成中',
            2 => '成功',
            3 => '失败'
        ];
        
        return $statusTexts[$status] ?? '未知状态';
    }
}

